home *** CD-ROM | disk | FTP | other *** search
Oberon Text | 1996-04-02 | 16.1 KB | 356 lines |
- Syntax10.Scn.Fnt
- Syntax10b.Scn.Fnt
- InfoElems
- Alloc
- Syntax10.Scn.Fnt
- StampElems
- Alloc
- 2 Apr 96
- "Title": CrazyFiller
- "Author": Christoph Steindl (CS)
- "Abstract": Implements a new handler for the filler viewers. Filler viewers are dummy viewers which are
- visible if no other viewers are on the screen (as well in the user track as in the system track). Then the
- filler viewers are painted with Mandlebrot sets. You can zoom into the figures selecting a rectangular
- area with the left mouse. You can restore the initial figure by pressing the setup button.
- "Keywords": filler
- "Version": 1.0
- "From": 02.02.95 16:26:50
- "Until":
- "Changes": selection is restricted so that zoomed area fits into the filler viewer without distortion
- "Hints": Use System.Open CrazyFiller.Tool
- Syntax10i.Scn.Fnt
- FoldElems
- Syntax10.Scn.Fnt
- redraw
- Syntax10.Scn.Fnt
- define new zooming area
- Syntax10.Scn.Fnt
- restore to full size
- MODULE CrazyFiller;
- (* Christoph Steindl (CS) 02.02.95 - 10 Feb 95 *)
- IMPORT Display, Viewers, Oberon, In, Out, Input;
- CONST
- ML = 2; MM = 1; MR = 0; (* mouse keys *)
- filler = 1;
- bound = 10;
- CrazyFiller* = POINTER TO CrazyFillerDesc;
- Drawer* = POINTER TO DrawerDesc;
- Region* = POINTER TO RegionDesc;
- DrawerDesc* = RECORD (Oberon.TaskDesc)
- filler: CrazyFiller;
- dx, dy: LONGREAL;
- END;
- CrazyFillerDesc* = RECORD;
- vwr: Viewers.Viewer;
- regions: Region;
- drawer: Drawer;
- xMin, xMax, yMin, yMax: LONGREAL
- END;
- RegionDesc* = RECORD
- x, y, w, h: INTEGER;
- next: Region
- END;
- fillerHandler: Display.Handler;
- userFiller, systemFiller: CrazyFiller;
- maxIter*: INTEGER;
- regsPerCycle*: INTEGER;
- PROCEDURE Min(x, y: INTEGER): INTEGER;
- BEGIN
- IF x < y THEN RETURN x ELSE RETURN y END
- END Min;
- PROCEDURE Max(x, y: INTEGER): INTEGER;
- BEGIN
- IF x > y THEN RETURN x ELSE RETURN y END
- END Max;
- PROCEDURE DrawMandelbrodt;
- VAR this: Drawer; p, q, h1, h2, x, y, x0, y0: LONGREAL; filler: CrazyFiller;
- region: Region; k1, k2, k3, k4, k5, i, j, count: INTEGER; allBlack: BOOLEAN;
- PROCEDURE Dot (col, x, y: INTEGER);
- BEGIN
- IF col = maxIter THEN
- Display.ReplConst(Display.white, x, y, 1, 1, Display.replace)
- ELSE
- Display.ReplConst(col MOD 15, x, y, 1, 1, Display.replace)
- END
- END Dot;
- PROCEDURE Eval (i, j: INTEGER; VAR k: INTEGER);
- BEGIN
- k := 0; x := 0; y := 0;
- p := filler.xMin + (i - filler.vwr.X) * this.dx; q := filler.yMin + (j - filler.vwr.Y) * this.dy;
- REPEAT
- h1 := x * x; h2 := y * y;
- x0 := h1 - h2 + p; y0 := 2 * x * y + q;
- x := x0; y := y0; INC(k)
- UNTIL (k >= maxIter) OR (h1 + h2 > bound);
- END Eval;
- PROCEDURE Divide (x, y, w, h: INTEGER; VAR regions: Region);
- VAR xHalf, yHalf: INTEGER; tmp: Region;
- BEGIN
- xHalf := w DIV 2; yHalf := h DIV 2;
- IF xHalf # 0 THEN
- IF yHalf # 0 THEN
- NEW(tmp); tmp.x := x; tmp.y := y; tmp.w := xHalf; tmp.h := yHalf;
- tmp.next := regions; regions := tmp;
- NEW(tmp); tmp.x := x + xHalf; tmp.y := y; tmp.w := w - xHalf; tmp.h := yHalf;
- tmp.next := regions; regions := tmp;
- NEW(tmp); tmp.x := x; tmp.y := y + yHalf; tmp.w := xHalf; tmp.h := h - yHalf;
- tmp.next := regions; regions := tmp;
- NEW(tmp); tmp.x := x + xHalf; tmp.y := y + yHalf; tmp.w := w - xHalf; tmp.h := h - yHalf;
- tmp.next := regions; regions := tmp;
- ELSE
- NEW(tmp); tmp.x := x; tmp.y := y; tmp.w := xHalf; tmp.h := 1;
- tmp.next := regions; regions := tmp;
- NEW(tmp); tmp.x := x + xHalf; tmp.y := y; tmp.w := w - xHalf; tmp.h := 1;
- tmp.next := regions; regions := tmp;
- END
- ELSE
- IF yHalf # 0 THEN
- NEW(tmp); tmp.x := x; tmp.y := y; tmp.w := 1; tmp.h := yHalf;
- tmp.next := regions; regions := tmp;
- NEW(tmp); tmp.x := x; tmp.y := y + yHalf; tmp.w := 1; tmp.h := h - yHalf;
- tmp.next := regions; regions := tmp;
- ELSE
- Eval(x, y, xHalf);
- Dot(xHalf, x, y)
- END
- END
- END Divide;
- BEGIN
- this := Oberon.CurTask(Drawer); filler := this.filler;
- region := filler.regions; filler.regions := filler.regions.next;
- count := regsPerCycle;
- WHILE (count > 0) & (region # NIL) DO
- Eval(region.x, region.y, k1); Eval(region.x + region.w - 1, region.y, k2);
- Eval(region.x, region.y + region.h - 1, k3); Eval(region.x + region.w - 1, region.y + region.h - 1, k4);
- Dot(k1, region.x, region.y); Dot(k2, region.x + region.w - 1, region.y);
- Dot(k3, region.x, region.y + region.h - 1); Dot(k4, region.x + region.w - 1, region.y + region.h - 1);
- allBlack := (k1 = k2) & (k2 = k3) & (k3 = k4);
- FOR i := region.x + 1 TO region.x + region.w - 2 DO
- Eval(i, region.y, k5); Dot(k5, i, region.y); allBlack := allBlack & (k5 = k1);
- Eval(i, region.y + region.h - 1, k5); Dot(k5, i, region.y + region.h - 1); allBlack := allBlack & (k5 = k1)
- END;
- FOR j := region.y + 1 TO region.y + region.h - 2 DO
- Eval(region.x, j, k5); Dot(k5, region.x, j); allBlack := allBlack & (k5 = k1);
- Eval(region.x + region.w - 1, j, k5); Dot(k5, region.x + region.w - 1, j); allBlack := allBlack & (k5 = k1)
- END;
- IF allBlack & (region.w > 2) & (region.h > 2) THEN
- IF k1 = maxIter THEN
- Display.ReplConst(Display.white, region.x + 1, region.y + 1, region.w - 2, region.h - 2, Display.replace)
- ELSE
- Display.ReplConst(k1 MOD 15, region.x + 1, region.y + 1, region.w - 2, region.h - 2, Display.replace)
- END
- ELSIF (region.w > 2) & (region.h > 2) THEN
- Divide(region.x + 1, region.y + 1, region.w - 2, region.h - 2, filler.regions);
- END;
- DEC(count); region := filler.regions;
- IF (filler.regions # NIL) & (count > 0) THEN filler.regions := filler.regions.next END
- END;
- IF region = NIL THEN Oberon.Remove(this) END
- END DrawMandelbrodt;
- PROCEDURE DragRect (filler: CrazyFiller; f: Display.Frame; x0, y0, x1, y1: INTEGER; VAR x2, y2: INTEGER;
- VAR keysum: SET);
- VAR keys: SET; x, y: INTEGER;
- PROCEDURE ReplConst(x, y, w, h: INTEGER);
- BEGIN
- IF w < 0 THEN x := x + w; w := - w END;
- IF h < 0 THEN y := y + h; h := - h END;
- IF (w # 0) & (h # 0) THEN Display.ReplConst(Display.white, x, y, w, h, Display.invert) END
- END ReplConst;
- PROCEDURE FlipRect(x0, y0, x1, y1, x2, y2: INTEGER);
- BEGIN
- ReplConst(x0 + 1, y1, x1 - x0 - 2, 1);
- ReplConst(x1 - 1, y1, 1, y0 - y1);
- ReplConst(x1 - 1, y0 - 1, x2 - x1, 1);
- ReplConst(x2 - 1, y2, 1, y0 - y2);
- ReplConst(x0 + 1, y2, x2 - x0 - 2, 1);
- ReplConst(x0, y2, 1, y1 - y2)
- END FlipRect;
- BEGIN
- keys := keysum;
- FlipRect(x0, y0, x0 + 1, y0 - 1, x1, y1); (* draw initial rectangle *)
- WHILE keys # {} DO
- Input.Mouse(keys, x, y);
- Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, x, y);
- keysum := keysum + keys;
- x2 := Min(Max(x, f.X), f.X + f.W); (* confine x2 to frame f *)
- y2 := Min(Max(y, f.Y), f.Y + f.H); (* confine y2 to frame f *)
- IF y2 < SHORT(ENTIER(y0 - ABS(x2 - x0) * filler.vwr.H / filler.vwr.W + 0.5)) THEN
- y2 := SHORT(ENTIER(y0 - ABS(x2 - x0) * filler.vwr.H / filler.vwr.W + 0.5))
- ELSIF y2 > SHORT(ENTIER(y0 + ABS(x2 - x0) * filler.vwr.H / filler.vwr.W + 0.5)) THEN
- y2 := SHORT(ENTIER(y0 + ABS(x2 - x0) * filler.vwr.H / filler.vwr.W + 0.5))
- END;
- IF x2 < SHORT(ENTIER(x0 - ABS(y2 - y0) * filler.vwr.W / filler.vwr. H + 0.5)) THEN
- x2 := SHORT(ENTIER(x0 - ABS(y2 - y0) * filler.vwr.W / filler.vwr. H + 0.5))
- ELSIF x2 > SHORT(ENTIER(x0 + ABS(y2 - y0) * filler.vwr.W / filler.vwr.H + 0.5)) THEN
- x2 := SHORT(ENTIER(x0 + ABS(y2 - y0) * filler.vwr.W / filler.vwr. H + 0.5))
- END;
- IF (x2 # x1) OR (y2 # y1) THEN
- FlipRect(x0, y0, x1, y1, x2, y2);
- x1 := x2; y1 := y2
- END
- END;
- FlipRect(x0, y0, x0 + 1, y0 - 1, x1, y1) (* erase spanned rectangle *)
- END DragRect;
- PROCEDURE InitDrawer* (VAR drawer: DrawerDesc; W, H: INTEGER;
- filler: CrazyFiller; draw: Oberon.Handler);
- BEGIN
- drawer.handle := draw; drawer.safe := FALSE;
- drawer.filler := filler;
- drawer.dx := (drawer.filler.xMax - drawer.filler.xMin) / W;
- drawer.dy := (drawer.filler.yMax - drawer.filler.yMin) / H;
- END InitDrawer;
- PROCEDURE InitFiller (filler: CrazyFiller; vwr: Viewers.Viewer);
- BEGIN
- filler.xMin := -2.25; filler.xMax := 0.75;
- filler.yMin := -1.125; filler.yMax := 1.125;
- filler.vwr := vwr;
- END InitFiller;
- PROCEDURE InstallCustomHandler* (h: Display.Handler);
- VAR m: Viewers.ViewerMsg;
- BEGIN
- IF h = fillerHandler THEN RETURN END;
- m.id := Viewers.restore;
- IF userFiller.regions # NIL THEN userFiller.regions := NIL; Oberon.Remove(userFiller.drawer) END;
- userFiller.vwr.handle := h; userFiller.vwr.handle(userFiller.vwr, m);
- IF systemFiller.regions # NIL THEN systemFiller.regions := NIL; Oberon.Remove(systemFiller.drawer) END;
- systemFiller.vwr.handle := h; systemFiller.vwr.handle(systemFiller.vwr, m)
- END InstallCustomHandler;
- PROCEDURE DefaultHandler* (f: Display.Frame; VAR m: Display.FrameMsg);
- BEGIN
- WITH f: Viewers.Viewer DO
- IF m IS Oberon.InputMsg THEN
- WITH m: Oberon.InputMsg DO
- IF m.id=Oberon.track THEN Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, m.X, m.Y) END
- END
- ELSIF m IS Oberon.ControlMsg THEN
- WITH m: Oberon.ControlMsg DO
- IF m.id=Oberon.mark THEN Oberon.DrawCursor(Oberon.Pointer, Oberon.Star, m.X, m.Y) END
- END
- ELSIF m IS Viewers.ViewerMsg THEN
- WITH m: Viewers.ViewerMsg DO
- IF (m.id=Viewers.restore) & (f.W > 0) & (f.H > 0) THEN Oberon.RemoveMarks(f.X, f.Y, f.W, f.H);
- Display.ReplConst(Display.black, f.X, f.Y, f.W, f.H, Display.replace)
- ELSIF (m.id=Viewers.modify) & (m.Y < f.Y) THEN Oberon.RemoveMarks(f.X, m.Y, f.W, f.Y-m.Y);
- Display.ReplConst(Display.black, f.X, m.Y, f.W, f.Y-m.Y, Display.replace)
- END
- END
- END
- END DefaultHandler;
- PROCEDURE CrazyHandler* (f: Display.Frame; VAR m: Display.FrameMsg);
- VAR drawer: Drawer; x, y: INTEGER; filler, oldFiller: CrazyFiller; redrawMsg: Viewers.ViewerMsg;
- PROCEDURE Redraw(y, h: INTEGER);
- VAR region: Region;
- BEGIN
- IF filler.regions # NIL THEN filler.regions := NIL; Oberon.Remove(filler.drawer) END;
- Oberon.RemoveMarks(f.X, f.Y, f.W, f.H);
- NEW(drawer); InitDrawer(drawer^, f.W, h, filler, DrawMandelbrodt);
- filler.drawer := drawer;
- NEW(region); region.x := f.X; region.y := y; region.w := f.W; region.h := h;
- filler.regions := region;
- Display.ReplConst(Display.black, f.X, y, f.W, h, Display.replace);
- Oberon.Install(drawer)
- END Redraw;
- BEGIN
- WITH f: Viewers.Viewer DO
- WITH m: Viewers.ViewerMsg DO
- IF f.X = 0 THEN filler := userFiller ELSE filler := systemFiller END;
- IF m.id = Viewers.restore THEN
- IF (f.W > 0) & (f.H > 0) THEN Redraw(f.Y, f.H)
- ELSE IF filler.regions # NIL THEN filler.regions := NIL; Oberon.Remove(filler.drawer) END
- END
- ELSIF m.id = Viewers.modify THEN Redraw(m.Y, m.H)
- ELSIF m.id = Viewers.suspend THEN
- IF filler.regions # NIL THEN filler.regions := NIL; Oberon.Remove(filler.drawer) END
- END
- | m: Oberon.InputMsg DO
- IF m.id = Oberon.track THEN (* mouse event *)
- Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, m.X, m.Y);
- IF ML IN m.keys THEN
- IF m.X < userFiller.vwr.X + userFiller.vwr.W THEN (* click in user filler *)
- filler := userFiller
- ELSE
- filler := systemFiller
- END;
- DragRect(filler, f, m.X, m.Y, m.X + 2, m.Y - 2, x, y, m.keys); (* m.X, m.Y is the upper
- left corner; x, y is the lower right corner *)
- IF m.keys # {ML, MM, MR} THEN
- NEW(oldFiller); oldFiller^ := filler^;
- filler.yMin := oldFiller.yMin + (oldFiller.yMax - oldFiller.yMin) / oldFiller.vwr.H * (Min(y, m.Y) - oldFiller.vwr.Y);
- filler.yMax := oldFiller.yMin + (oldFiller.yMax - oldFiller.yMin) / oldFiller.vwr.H * (Max(y, m.Y) - oldFiller.vwr.Y);
- filler.xMin := oldFiller.xMin + (oldFiller.xMax - oldFiller.xMin) / oldFiller.vwr.W * (Min(x, m.X) - oldFiller.vwr.X);
- filler.xMax := oldFiller.xMin + (oldFiller.xMax - oldFiller.xMin) / oldFiller.vwr.W * (Max(x, m.X) - oldFiller.vwr.X);
- redrawMsg.id := Viewers.restore;
- filler.vwr.handle(filler.vwr, redrawMsg);
- END
- END
- ELSE DefaultHandler(f, m)
- END
- | m: Oberon.ControlMsg DO
- IF m.id = Oberon.neutralize THEN
- userFiller.xMin := -2.25; userFiller.xMax := 0.75;
- userFiller.yMin := -1.125; userFiller.yMax := 1.125;
- systemFiller.xMin := -2.25; systemFiller.xMax := 0.75;
- systemFiller.yMin := -1.125; systemFiller.yMax := 1.125;
- redrawMsg.id := Viewers.restore;
- userFiller.vwr.handle(userFiller.vwr, redrawMsg);
- systemFiller.vwr.handle(systemFiller.vwr, redrawMsg)
- ELSE DefaultHandler(f, m)
- END
- ELSE DefaultHandler(f, m)
- END
- END CrazyHandler;
- PROCEDURE InstallDefault*;
- BEGIN InstallCustomHandler(DefaultHandler) END InstallDefault;
- PROCEDURE InstallCrazy*;
- BEGIN InstallCustomHandler(CrazyHandler) END InstallCrazy;
- PROCEDURE SetMaxIter*;
- BEGIN
- In.Open; In.Int(maxIter)
- END SetMaxIter;
- PROCEDURE SetRegsPerCycle*;
- BEGIN
- In.Open; In.Int(regsPerCycle)
- END SetRegsPerCycle;
- PROCEDURE ShowParams*;
- BEGIN
- IF (userFiller.vwr # NIL) & (userFiller.vwr.H > 0) THEN
- Out.Ln; Out.String("User filler:");
- Out.Ln; Out.String(" Range:");
- Out.Ln; Out.String(" xMin = "); Out.LongReal(userFiller.xMin, 20);
- Out.String(", xMax = "); Out.LongReal(userFiller.xMax, 20);
- Out.Ln; Out.String(" yMin = "); Out.LongReal(userFiller.yMin, 20);
- Out.String(", yMax = "); Out.LongReal(userFiller.yMax, 20);
- Out.Ln; Out.String(" Height: "); Out.Int(userFiller.vwr.H, 0);
- Out.Ln; Out.String(" Width: "); Out.Int(userFiller.vwr.W, 0);
- Out.Ln; Out.String(" Iterations: "); Out.Int(maxIter, 0);
- Out.Ln; Out.String(" Bound: "); Out.Int(bound, 0);
- Out.Ln; Out.String(" Rectangles per cycle: "); Out.Int(regsPerCycle, 0)
- END;
- IF (systemFiller.vwr # NIL) & (systemFiller.vwr.H > 0) THEN
- Out.Ln; Out.String("System filler:");
- Out.Ln; Out.String(" Range:");
- Out.Ln; Out.String(" xMin = "); Out.LongReal(systemFiller.xMin, 20);
- Out.String(", xMax = "); Out.LongReal(systemFiller.xMax, 20);
- Out.Ln; Out.String(" yMin = "); Out.LongReal(systemFiller.yMin, 20);
- Out.String(", yMax = "); Out.LongReal(systemFiller.yMax, 20);
- Out.Ln; Out.String(" Height: "); Out.Int(systemFiller.vwr.H, 0);
- Out.Ln; Out.String(" Width: "); Out.Int(systemFiller.vwr.W, 0);
- Out.Ln; Out.String(" Iterations: "); Out.Int(maxIter, 0);
- Out.Ln; Out.String(" Bound: "); Out.Int(bound, 0);
- Out.Ln; Out.String(" Rectangles per cycle: "); Out.Int(regsPerCycle, 0)
- END ShowParams;
- PROCEDURE Init;
- VAR cur: Viewers.Viewer;
- BEGIN
- fillerHandler := NIL; maxIter := 100; regsPerCycle := 20;
- NEW(userFiller); NEW(systemFiller);
- cur := Viewers.This(0, 0); WHILE cur.state # filler DO cur := Viewers.Next(cur) END;
- InitFiller(userFiller, cur);
- cur := Viewers.This(cur.W, 0); WHILE cur.state # filler DO cur := Viewers.Next(cur) END;
- InitFiller(systemFiller, cur)
- END Init;
- BEGIN
- Init
- END CrazyFiller.InstallCrazy CrazyFiller.InstallDefault CrazyFiller.ShowParams
- CrazyFiller.SetMaxIter 30
-